package yunjiao.javatutorials.guava.concurrent.log;

import yunjiao.javatutorials.guava.concurrent.ForwardingLock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;

/**
 * Builder模式配置
 *
 * @author yangyunjiao
 */
public class ConfigurableLoggingLock extends ForwardingLock {
    private final Lock delegate;
    private final String name;
    private final Consumer<String> logger;
    private final boolean logLockAttempts;
    private final boolean logLockAcquisitions;
    private final boolean logReleases;

    public static class Builder {
        private final Lock delegate;
        private String name = "AnonymousLock";
        private Consumer<String> logger = System.out::println;
        private boolean logLockAttempts = true;
        private boolean logLockAcquisitions = true;
        private boolean logReleases = true;

        public Builder(Lock delegate) {
            this.delegate = delegate;
        }

        public Builder name(String name) {
            this.name = name;
            return this;
        }

        public Builder logger(Consumer<String> logger) {
            this.logger = logger;
            return this;
        }

        public Builder logLockAttempts(boolean enabled) {
            this.logLockAttempts = enabled;
            return this;
        }

        public Builder logLockAcquisitions(boolean enabled) {
            this.logLockAcquisitions = enabled;
            return this;
        }

        public Builder logReleases(boolean enabled) {
            this.logReleases = enabled;
            return this;
        }

        public ConfigurableLoggingLock build() {
            return new ConfigurableLoggingLock(this);
        }
    }

    private ConfigurableLoggingLock(Builder builder) {
        this.delegate = builder.delegate;
        this.name = builder.name;
        this.logger = builder.logger;
        this.logLockAttempts = builder.logLockAttempts;
        this.logLockAcquisitions = builder.logLockAcquisitions;
        this.logReleases = builder.logReleases;
    }

    @Override
    protected Lock delegate() {
        return delegate;
    }

    @Override
    public void lock() {
        if (logLockAttempts) {
            logger.accept("[" + name + "] 尝试获取锁...");
        }

        long startTime = System.currentTimeMillis();
        super.lock();
        long endTime = System.currentTimeMillis();

        if (logLockAcquisitions) {
            logger.accept("[" + name + "] 锁获取成功，耗时 " + (endTime - startTime) + "ms");
        }
    }

    @Override
    public void unlock() {
        if (logReleases) {
            logger.accept("[" + name + "] 释放锁");
        }
        super.unlock();
    }

    @Override
    public boolean tryLock() {
        if (logLockAttempts) {
            logger.accept("[" + name + "] 尝试非阻塞获取锁...");
        }
        boolean result = super.tryLock();
        if (logLockAcquisitions) {
            logger.accept("[" + name + "] tryLock 结果: " + result);
        }
        return result;
    }

    public static void main(String[] args) throws InterruptedException {
        ConfigurableLoggingLock lock = new ConfigurableLoggingLock.Builder(new ReentrantLock())
                .name("HighlyConfigurableLock")
                .logger(msg -> System.err.println("[ERROR_LOG] " + msg)) // 重定向到错误输出
                .logLockAttempts(true)
                .logLockAcquisitions(true)
                .logReleases(false) // 不记录释放操作
                .build();

        lock.lock();
        try {
            System.out.println("执行操作...");
        } finally {
            lock.unlock(); // 这个解锁操作不会被记录
        }
    }
}
